

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <!-- meta http-equiv="refresh" content="900" -->
    <title>Skeleton Stream Demo火柴人动画在线直播演示-SUNSHILE SILICON</title>
    <script src="./static/js/jquery.min.js"></script>
    <script src="./static/js/mqttws31.min.js"></script>
    <script src="./static/js/polyfill.min.js"></script>

  </head>
  <body style="overflow: hidden">
    <div id="box" style="width: 1080px; height: 606px; margin: auto">
      <canvas id="canvas" width="1080" height="606"></canvas>
    </div>

 
    <script type="text/javascript" language="javascript">
      /*****************************************************************************************
       * You must replace parameters with your own. Refer to the FAQ for more detail on how to configure them:
       * http://www.sunsili.com/doc_3.html
       * For demo, these settings are configured to an AltumView account on the Canadian server.
       * If you do not see any skeleton rendering, the sensor is no longer available.
       *
       * Last updated: March 18, 2022 by Andrew A.
       ******************************************************************************************/

      // 获取url参数
      const oauthUrl = "https://oauth.ailecare.cn/v1.0";
      const apiUrl = "https://api.ailecare.cn/v1.0";
      const mqttUrl = "beijing.altumview.com.cn";
      const clientSecret = "PL2F9PIMUChFYdSqwT9*******rJIt2";  
      const clientId = "Am2H****F";
      const cusname = new URLSearchParams(window.location.search).get('cusname') || ''
      const serialNumber = "23DBD754B3BF74EE"; // Use the mobile app to get the serial number
      const streamToken = "1178470350"; // Call GET '/cameras/:id/streamtoken' endpoint to get Stream Token
      const groupId = 4614; // Call GET '/info' endpoint to get Group ID
      const cameraId = 23784;
      //const canvasWidth =  1080; // 960;
      //const canvasHeight = 606; // 540;
      const skeletonLineWidth = 16;
      const appType = new URLSearchParams(window.location.search).get('appType') || ''

      let canvasWidth = window.innerWidth-16
      let canvasHeight = window.innerHeight-16
      let time_out = null
      let mqttNew = null
      let time_out_resize = null
/*
      if (appType === 'app') {
        canvasHeight = canvasHeight / 2.5
        canvasWidth = canvasWidth // - 20
      } else {
        canvasWidth = canvasHeight * 16 / 9 // 使用16:9的比例计算宽度
        if(canvasWidth > window.innerWidth)
        {
            canvasWidth = window.innerWidth
            canvasHeight = canvasWidth * 9 /16
        }
      }
*/
        canvasWidth = canvasHeight * 16 / 9 // 使用16:9的比例计算宽度
        if(canvasWidth > (window.innerWidth-16))
        {
            canvasWidth = window.innerWidth-16
            canvasHeight = canvasWidth * 9 / 16
        }
      document.getElementById('box').style.height = canvasHeight + 'px'
      document.getElementById('box').style.width = canvasWidth + 'px'
      document.getElementById('canvas').height = canvasHeight
      document.getElementById('canvas').width = canvasWidth

      const getCredentials = () => {
        if (mqttNew) {
          try {
            mqttNew.disconnect()
          } catch (error) {}
        }
        $.ajax({
          type: 'POST',
          url: `${oauthUrl}/token`,
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
          },
          data: {
            client_id: clientId,
            client_secret: clientSecret,
            grant_type: 'client_credentials',
            scope: 'camera:write camera:read',
          },
          success: function (response) {
            token = response.access_token
            console.log('token', token)
            var url = `${apiUrl}/mqttAccount`
            var xhr = new XMLHttpRequest()
            xhr.open('GET', url)
            xhr.setRequestHeader('Authorization', 'Bearer ' + token)
            xhr.onreadystatechange = function () {
              if (xhr.readyState === 4) {
                console.log(xhr.responseText)
                const response = JSON.parse(xhr.responseText)
                username = response.data.mqtt_account.username
                password = response.data.mqtt_account.passcode

                const onFailure = () => {
                  const reconnectTimeout = 2000
                  console.log('Connect failed. Trying to reconnect after 2 sec')
                  setTimeout(MQTTConnect, reconnectTimeout)
                }

                const onMessageArrived = (message) => {
                  const byteList = message.payloadBytes
                  const frameNum = parseStringInt32(byteList, 0)
                  const numPeople = parseStringInt32(byteList, 4)

                  const people = []
                  for (let i = 0; i < numPeople; i++) {
                    const pos = 8 + 152 * i
                    const personId = parseStringInt32(byteList, pos)
                    const person = {}
                    for (let j = 0; j < 18; j++) {
                      const x = parseStringFloat(byteList, pos + 8 + j * 4)
                      const y = parseStringFloat(byteList, pos + 80 + j * 4)
                      if (x && y) person[j] = new Point(x, y)
                    }
                    person.name = personId
                    people.push(person)
                  }

                  const canvas = document.getElementById('canvas')
                  if (canvas && people) {
                    const ctx = canvas.getContext('2d')
                    ctx.clearRect(0, 0, canvasWidth, canvasHeight)

                    people.forEach((person) => {
                      drawSkeleton(ctx, skeletonLineWidth, person)
                    })
                  }
                }

                const drawSkeleton = (ctx, lineWidth, points) => {
                  ctx.lineWidth = lineWidth
                  ctx.lineCap = 'round'

                  let minX = 1
                  let minY = 1
                  pointPairs.forEach((pair) => {
                    const startPoint = points[pair.start]
                    const endPoint = points[pair.end]
                    if (startPoint !== undefined && endPoint !== undefined) {
                      if (endPoint.x < minX) minX = endPoint.x
                      if (endPoint.y < minY) minY = endPoint.y
                      ctx.strokeStyle = pair.color
                      drawLine(ctx, startPoint.x * canvasWidth, startPoint.y * canvasHeight, endPoint.x * canvasWidth, endPoint.y * canvasHeight)
                    }
                  })
                }

                function Point(x, y) {
                  this.x = x
                  this.y = y
                }

                const drawLine = (ctx, x0, y0, x1, y1) => {
                  ctx.beginPath()
                  ctx.moveTo(x0, y0)
                  ctx.lineTo(x1, y1)
                  ctx.stroke()
                }

                const pointPairs = [
                  { start: 0, end: 1, color: 'pink' },
                  { start: 1, end: 2, color: 'orange' },
                  { start: 2, end: 3, color: 'yellow' },
                  { start: 3, end: 4, color: 'lightYellow' },
                  { start: 1, end: 5, color: 'darkSalmon' },
                  { start: 5, end: 6, color: 'salmon' },
                  { start: 6, end: 7, color: 'lightSalmon' },
                  { start: 1, end: 8, color: 'darkTurquoise' },
                  { start: 8, end: 9, color: 'turquoise' },
                  { start: 9, end: 10, color: 'paleTurquoise' },
                  { start: 1, end: 11, color: 'darkRed' },
                  { start: 11, end: 12, color: 'red' },
                  { start: 12, end: 13, color: 'orange' },
                  { start: 0, end: 14, color: 'purple' },
                  { start: 14, end: 16, color: 'purple' },
                  { start: 0, end: 15, color: 'violet' },
                  { start: 15, end: 17, color: 'violet' },
                ]

                const parseStringInt32 = (stringData, startIndex) => {
                  const t = stringData.slice(startIndex, startIndex + 4)
                  return new DataView(t.buffer).getInt32(0, true)
                }

                const parseStringFloat = (stringData, startIndex) => {
                  const t = stringData.slice(startIndex, startIndex + 4)
                  return new DataView(t.buffer).getFloat32(0, true)
                }

                const onConnect = () => {
                  console.log('connect success')
                  var soptions = {
                    qos: 0,
                  }

                  // Next, subscribe to this topic with the aforementioned stream token appended
                  const subscribeTopic = `mobileClient/${groupId}/camera/${serialNumber}/skeleton/${streamToken}`
                  mqtt.subscribe(subscribeTopic, soptions)

                  console.log(`subscribe to ${subscribeTopic}`)
                  // Finally, publish the same stream token as a message to the camera in order to start streaming. You must publish this message every 45 seconds to keep streaming going.
                  const publishTopic = `mobile/${groupId}/camera/${serialNumber}/token/mobileStreamToken`
                  message = new Paho.MQTT.Message(streamToken)
                  message.destinationName = publishTopic
                  message.qos = 2
                  message.retained = false
                  mqtt.send(message)

                  console.log('Connected')

                  const reconnectTimeout = 90000
                  setTimeout(MQTTConnect, reconnectTimeout)
                }

                const MQTTConnect = async (id) => {
                  const port = 8084
                  console.log(`connecting to ${mqttUrl}:${port}`)
                  mqtt = new Paho.MQTT.Client(mqttUrl, port, username)
                  mqttNew = mqtt
                  const options = {
                    timeout: 3,
                    onSuccess: onConnect,
                    onFailure: onFailure,
                    useSSL: true,
                    userName: username,
                    password: password,
                  }
                  mqtt.onMessageArrived = onMessageArrived
                  mqtt.connect(options)
                }
                MQTTConnect(1)
              }
            }
            xhr.send()
            if (cameraId) {
              $.ajax({
                type: 'GET',
                url: `${apiUrl}/cameras/${cameraId}/background`,
                headers: {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  Authorization: 'Bearer ' + token,
                },
                success: (res) => {
                  // console.log('img', res)
                  let img = res.data.background_url
                  let dom = document.getElementById('box')
                  dom.style.backgroundImage = `url('${img}')`
                  dom.style.backgroundSize = '100% 100%'
                  dom.style.transform = 'rotateY(180deg)'
                },
              })
            }
          },
          error: function (errorThrown) {
            alert(JSON.stringify(errorThrown.error()))
          },
        })
      }

      getCredentials()
    </script>
  </body>
</html>
